package io.shuttle.mbe.api

import io.shuttle.mbe.api.types.StringOrStringArr
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.VoidFunction

////////////////////
// Declarative Web Request
////////////////////
/**
 * Use the `Browser.declarativeWebRequest` API to intercept, block, or modify requests in-flight. It is significantly faster than the Browser.webRequest API because you can register rules that are evaluated in the browser rather than the JavaScript engine, which reduces roundtrip latencies and allows higher efficiency.
 *
 * Permissions: "declarativeWebRequest"
 *
 * MV2 only
 * @deprecated Check out the {@link declarativeNetRequest} API instead
 */
interface DeclarativeWebRequest {

    // Adds a cookie to the request or overrides a cookie, in case another cookie of the same name exists already. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    // @return Cookie to be added to the request. No field may be undefined.
    data class AddRequestCookie(
        var cookie: RequestCookie
    )

    // Adds a cookie to the response or overrides a cookie, in case another cookie of the same name exists already. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    // @return Cookie to be added to the response. The name and value need to be specified.
    data class AddResponseCookie(
        // Cookie to be added to the response. The name and value need to be specified.
        var cookie: ResponseCookie
    )

    // Adds the response header to the response of this web request. As multiple response headers may share the same name, you need to first remove and then add a new response header in order to replace one.
    data class AddResponseHeader(
        // HTTP response header name.
        var name: String,
        // HTTP response header value.
        var value: String,
    )

    // Declarative event action that cancels a network request.
    class CancelRequest

    // Edits one or more cookies of request. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    data class EditRequestCookie(
        // Filter for cookies that will be modified. All empty entries are ignored.
        var filter: RequestCookie,
        // Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed.
        var modification: RequestCookie,
    )

    // Edits one or more cookies of response. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    data class EditResponseCookie(
        // Filter for cookies that will be modified. All empty entries are ignored.
        var filter: FilterResponseCookie,
        // Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed.
        var modification: ResponseCookie,
    )

    // A filter of a cookie in HTTP Responses.
    data class FilterResponseCookie(
        // Inclusive lower bound on the cookie lifetime (specified in seconds after current time). Only cookies whose expiration date-time is set to 'now + ageLowerBound' or later fulfill this criterion. Session cookies do not meet the criterion of this filter. The cookie lifetime is calculated from either 'max-age' or 'expires' cookie attributes. If both are specified, 'max-age' is used to calculate the cookie lifetime.
        var ageLowerBound: Number?,
        // Inclusive upper bound on the cookie lifetime (specified in seconds after current time). Only cookies whose expiration date-time is in the interval [now, now + ageUpperBound] fulfill this criterion. Session cookies and cookies whose expiration date-time is in the past do not meet the criterion of this filter. The cookie lifetime is calculated from either 'max-age' or 'expires' cookie attributes. If both are specified, 'max-age' is used to calculate the cookie lifetime.
        var ageUpperBound: Number?,
        // Value of the Domain cookie attribute.
        var domain: String?,
        // Value of the Expires cookie attribute.
        var expires: String?,
        // Existence of the HttpOnly cookie attribute.
        var httpOnly: String?,
        // Value of the Max-Age cookie attribute
        var maxAge: Number?,
        // Name of a cookie.
        var name: String?,
        // Value of the Path cookie attribute.
        var path: String?,
        // Existence of the Secure cookie attribute.
        var secure: String?,
        // Filters session cookies. Session cookies have no lifetime specified in any of 'max-age' or 'expires' attributes.
        var sessionCookie: Boolean?,
        // Value of a cookie, may be padded in double-quotes.
        var value: String?,
    )

    // Filters request headers for various criteria. Multiple criteria are evaluated as a conjunction.
    data class HeaderFilter(
        // Matches if the header name contains all of the specified strings.
        var nameContains: StringOrStringArr?,
        // Matches if the header name is equal to the specified string.
        var nameEquals: String?,
        // Matches if the header name starts with the specified string.
        var namePrefix: String?,
        // Matches if the header name ends with the specified string.
        var nameSuffix: String?,
        // Matches if the header value contains all of the specified strings.
        var valueContains: StringOrStringArr?,
        // Matches if the header value is equal to the specified string.
        var valueEquals: String?,
        // Matches if the header value starts with the specified string.
        var valuePrefix: String?,
        // Matches if the header value ends with the specified string.
        var valueSuffix: String?,
    )

    // Masks all rules that match the specified criteria.
    data class IgnoreRules(
        // If set, rules with the specified tag are ignored. This ignoring is not persisted, it affects only rules and their actions of the same network request stage. Note that rules are executed in descending order of their priorities. This action affects rules of lower priority than the current rule. Rules with the same priority may or may not be ignored.
        var hasTag: String?,
        // If set, rules with a lower priority than the specified value are ignored. This boundary is not persisted, it affects only rules and their actions of the same network request stage.
        var lowerPriorityThan: Number?,
    )

    // Redirects a request by applying a regular expression on the URL. The regular expressions use the RE2 syntax.
    data class RedirectByRegEx(
        // A match pattern that may contain capture groups. Capture groups are referenced in the Perl syntax ($1, $2, ...) instead of the RE2 syntax (\1, \2, ...) in order to be closer to JavaScript Regular Expressions.
        var from: String,
        // Destination pattern.
        var to: String,
    )

    // Declarative event action that redirects a network request.
    data class RedirectRequest(
        // Destination to where the request is redirected.
        var redirectUrl: String,
    )

    // Declarative event action that redirects a network request to an empty document.
    class RedirectToEmptyDocument

    // Declarative event action that redirects a network request to a transparent image.
    class RedirectToTransparentImage

    // Removes one or more cookies of request. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    data class RemoveRequestCookie(
        // Filter for cookies that will be removed. All empty entries are ignored.
        var filter: RequestCookie
    )

    // Removes the request header of the specified name. Do not use SetRequestHeader and RemoveRequestHeader with the same header name on the same request. Each request header name occurs only once in each request.
    data class RemoveRequestHeader(
        // HTTP request header name (case-insensitive).
        var name: String,
    )

    // Removes one or more cookies of response. Note that it is preferred to use the Cookies API because this is computationally less expensive.
    data class RemoveResponseCookie(
        // Filter for cookies that will be removed. All empty entries are ignored.
        var filter: FilterResponseCookie
    )

    // Removes all response headers of the specified names and values.
    data class RemoveResponseHeader(
        // HTTP request header name (case-insensitive).
        var name: String,
        // HTTP request header value (case-insensitive).
        var value: String?,
    )

    // A filter or specification of a cookie in HTTP Requests.
    data class RequestCookie(
        // Name of a cookie.
        var name: String,
        // Value of a cookie, may be padded in double-quotes.
        var value: String?,
    )

    // Matches network events by various criteria.
    data class RequestMatcher(
        // Matches if the MIME media type of a response (from the HTTP Content-Type header) is contained in the list.
        var contentType: List<String>?,
        // Matches if the MIME media type of a response (from the HTTP Content-Type header) is not contained in the list.
        var excludeContentType: List<String>,
        // Matches if none of the request headers is matched by any of the HeaderFilters.
        var excludeRequestHeaders: List<HeaderFilter>?,
        // Matches if none of the response headers is matched by any of the HeaderFilters.
        var excludeResponseHeaders: List<HeaderFilter>?,
        // Matches if the conditions of the UrlFilter are fulfilled for the 'first party' URL of the request. The 'first party' URL of a request, when present, can be different from the request's target URL, and describes what is considered 'first party' for the sake of third-party checks for cookies.
        @Deprecated("Ignored since release 82.")
        var firstPartyForCookiesUrl: Events.UrlFilter?,
        // Matches if some of the request headers is matched by one of the HeaderFilters.
        var requestHeaders: List<HeaderFilter>?,
        // Matches if the request type of a request is contained in the list. Requests that cannot match any of the types will be filtered out.
        var resourceType: List<ResourceType>?,
        // Matches if some of the response headers is matched by one of the HeaderFilters.
        var responseHeaders: List<HeaderFilter>?,
        // Contains a list of strings describing stages. Allowed values are 'onBeforeRequest', 'onBeforeSendHeaders', 'onHeadersReceived', 'onAuthRequired'. If this attribute is present, then it limits the applicable stages to those listed. Note that the whole condition is only applicable in stages compatible with all attributes.
        var stages: List<Stage>?,
        // If set to true, matches requests that are subject to third-party cookie policies. If set to false, matches all other requests.
        @Deprecated("Ignored since release 87.")
        var thirdPartyForCookies: Boolean?,
        // Matches if the conditions of the UrlFilter are fulfilled for the URL of the request.
        var url: Events.UrlFilter?,
    )

    // A specification of a cookie in HTTP Responses.
    data class ResponseCookie(
        // Value of the Domain cookie attribute.
        var domain: String?,
        // Value of the Expires cookie attribute.
        var expires: String?,
        // Existence of the HttpOnly cookie attribute.
        var httpOnly: String?,
        // Value of the Max-Age cookie attribute
        var maxAge: Number?,
        // Name of a cookie.
        var name: String?,
        // Value of the Path cookie attribute.
        var path: String?,
        // Existence of the Secure cookie attribute.
        var secure: String?,
        // Filters session cookies. Session cookies have no lifetime specified in any of 'max-age' or 'expires' attributes.
        var sessionCookie: Boolean?,
        // Value of a cookie, may be padded in double-quotes.
        var value: String?,
    )

    // Triggers the declarativeWebRequest.onMessage event.
    data class SendMessageToExtension(
        // The value that will be passed in the message attribute of the dictionary that is passed to the event handler.
        var message: String,
    )

    // Sets the request header of the specified name to the specified value. If a header with the specified name did not exist before, a new one is created. Header name comparison is always case-insensitive. Each request header name occurs only once in each request.
    data class SetRequestHeader(
        // HTTP request header name.
        var name: String,
        // HTTP request header value.
        var value: String,
    )

    enum class Stage {
        onBeforeRequest,
        onBeforeSendHeaders,
        onHeadersReceived,
        onAuthRequired,
    }

    // Fired when a message is sent via declarativeWebRequest.SendMessageToExtension from an action of the declarative web request API.
    abstract val onMessage: Events.Event<Value1Function<OnMessageCallbackData>>

    // Provides the Declarative Event API consisting of addRules, removeRules, and getRules.
    abstract val onRequest: Events.Event<VoidFunction>

    data class OnMessageCallbackData(
        // A UUID of the document that made the request.
        var documentId: String?,
        // The lifecycle the document is in.
        var documentLifecycle: Any, // FIXME: 实现 extensionTypes.DocumentLifecycle
        // The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab.
        var frameId: Number,
        // The type of frame the navigation occurred in.
        var frameType: ExtensionTypes.FrameType, // extensionTypes.FrameType
        // The message sent by the calling script.
        var message: String,
        // Standard HTTP method.
        var method: String,
        // A UUID of the parent document owning this frame. This is not set if there is no parent.
        var parentDocumentId: String?,
        // ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists.
        var parentFrameId: Number,
        // The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request.
        var requestId: String,
        // The stage of the network request during which the event was triggered.
        var stage: Stage,
        // The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab.
        var tabId: Number,
        // The time when this signal is triggered, in milliseconds since the epoch.
        var timeStamp: Number,
        // How the requested resource will be used.
        var type: ResourceType,
        var url: String
    )

    enum class OnRequestRuleAction {
        AddRequestCookie,
        AddResponseCookie,
        AddResponseHeader,
        CancelRequest,
        EditRequestCookie,
        EditResponseCookie,
        RedirectRequest,
        RedirectToTransparentImage,
        RedirectToEmptyDocument,
        RedirectByRegEx,
        RemoveRequestCookie,
        RemoveResponseCookie,
        RemoveRequestHeader,
        RemoveResponseHeader,
        SetRequestHeader,
        SendMessageToExtension,
        IgnoreRules,
    }

    enum class ResourceType {
        mainFrame,
        subFrame,
        stylesheet,
        script,
        image,
        font,
        `object`,
        xmlhttprequest,
        ping,
        cspReport,
        media,
        websocket,
        other
    }
}